<?php
class App_Source_Articles_Mapper extends Mozg_Mapper_Data
{
	private $_source;

	protected $_entityPath = 'entity/article';
	protected $_filterPath = 'filter/article';

	public function __construct()
	{
		$this->_source = Mozg_Source::get('default');
	}

	private function GetSqlFromFilter($filter = null)
	{
		$sqlFilter = array('where' => array(), 'join' => array());
		if (!($filter instanceof Mozg_Property_Params)) $filter = $this->GetFilter($filter);

		if ($filter->HasSet('id'))
		{
			$sqlFilter['where'][] = 'mae.id = ' .(int)$filter->GetId();
		}

		if (sizeof($filter->GetIds()))
		{
			$ids = array_map('intval', $filter->GetIds());
			$sqlFilter['where'][] = "mae.id in (" .implode(',', $ids). ")";
		}

		if ($filter->HasSet('url'))
		{
			$sqlFilter['where'][] = 'mae.url = ' .$this->_source->quote($filter->GetUrl());
		}

		$sqlFilter['where'][] = 'mae.blog_id = ' .(int)$filter->GetBlogId();

		$tagsArr = Mozg_Mapper::Get('Tags')->GetSearchArr($filter->GetTags());
		if (sizeof($tagsArr))
		{
			$searchStr = '';
			foreach ($tagsArr as $tag)
			{
				$searchStr .= '+",' .trim($this->_source->quote($tag), "'"). '," ';
			}
			$sqlFilter['where'][] = "MATCH(mae.tags_norm) AGAINST('" .$searchStr. "' IN BOOLEAN MODE)";
		}

		if (($filter->GetFromDate() !== null)
			&& ($filter->GetFromDate() !== false))
		{
			$sqlFilter['where'][] = 'mae.date_published >= ' .$this->_source->quote(Mozg::Lib('date')->Format($filter->GetFromDate(), 'Y-m-d H:i'));
		}

		if (($filter->GetToDate() !== null)
			&& ($filter->GetToDate() !== false))
		{
			$sqlFilter['where'][] = 'mae.date_published <= ' .$this->_source->quote(Mozg::Lib('date')->Format($filter->GetToDate(), 'Y-m-d H:i'));
		}

		if ($filter->GetCategory() && !$filter->GetBlogId())
		{
			$sqlFilter['join'][] = "INNER JOIN %%article_category%% mac on (mae.id = mac.entry_id)";
			$sqlFilter['where'][] = 'mac.category_id = ' .(int)$filter->GetCategory();
		}

		$sqlFilter['where'] = sizeof($sqlFilter['where']) ? '(' .implode(') and (', $sqlFilter['where']). ')' : '';
		$sqlFilter['join'] = sizeof($sqlFilter['join']) ?  implode(' ', $sqlFilter['join']) : '';

		return $sqlFilter;
	}

	private $_totalRows;

	public function GetTotalRows()
	{
		if (!is_int($this->_totalRows))
		{
			$this->_totalRows = $this->_source->query("SELECT FOUND_ROWS()")->fetchColumn();
		}

		return $this->_totalRows;
	}

	protected function Find($filter = null, Mozg_Paginator $paginator = null, $fields = array(), $langs = 0)
	{
		$sqlFilter = $this->GetSqlFromFilter($filter);

		$this->_totalRows = null;

		$rows = $this->_source->fetchObjectAll("SELECT " .($paginator ? "SQL_CALC_FOUND_ROWS" : "" ). "
												" .$this->_source->Table('articles')->GetSqlMap($fields, 'mae', '', $langs). ",
												" .$this->_source->Table('media')->GetSqlMap(array('tags_norm' => 0), "mm", "media"). "
					                     FROM
					                     	%%article_entry%% mae
					                     		LEFT JOIN %%media%% mm ON(mae.media_id = mm.id)
					                     		" .($sqlFilter['join'] ? $sqlFilter['join'] : ""). "
					                     " .($sqlFilter['where'] ? " WHERE ". $sqlFilter['where'] : ""). "
					                     ORDER BY mae.date_published DESC
					                     " .($paginator ? "LIMIT " .$paginator->GetSqlLimit() : ""), $this->_entityPath);

        return $rows;
	}

	public function GetList($filter = null, Mozg_Paginator $paginator = null)
	{
		return $this->Find($filter, $paginator, array('media_id' => 0, 'content' => 0, "related_entries" => 0, "media_ids" => 0));
	}

	public function GetOne($filter = null)
	{
		return current($this->Find($filter, new Mozg_Paginator(1,1), array('media_id' => 0), 1));
	}

	public function GetEntity($data = null)
	{
		$obj = parent::GetEntity($data);
		$obj->SetPublishDate(time());
		return $obj;
	}

	public function Save(Mozg_Property_Params $obj)
	{
		if (!$obj->Validator()->Validate()) return false;

		$this->Prepare($obj);

		if ($obj->GetId())
		{
			$filter = $this->GetFilter();
			$filter->SetId($obj->GetId());
			$filter->SetBlogId($obj->GetBlogId());
			return $this->Update($obj, $filter);
		}

		return $this->Insert($obj);
	}

	protected function Insert(Mozg_Property_Params $obj)
	{
		$addFields = array(
			'tags_norm' => Mozg_Mapper::Get('Tags')->GetSearchStr($obj->GetTags()),
			'categories_norm' => Mozg_Mapper::Get('Tags')->GetSearchStr($obj->GetCategories()),
		);

		$fields = $this->_source->Table('articles')->GetSqlInsert($obj, '', null, $addFields);
		$num = $this->_source->exec("INSERT INTO %%article_entry%%(" .$fields['fields']. ") VALUES (" .$fields['values']. ")");

		if ($num)
		{
			$obj->SetId($this->_source->lastInsertID());

			Mozg_Mapper::Get('Tags')->Save('articles', $obj->GetId(), $obj->GetTags());
			$this->SetEntryCategories($obj->GetId(), $obj->GetCategories());

			return true;
		}

		return false;
	}

	protected function Update(Mozg_Property_Params $obj, $filter = null)
	{
		$sqlFilter = $this->GetSqlFromFilter($filter);

		$addFields = array(
			'tags_norm' => Mozg_Mapper::Get('Tags')->GetSearchStr($obj->GetTags()),
			'categories_norm' => Mozg_Mapper::Get('Tags')->GetSearchStr($obj->GetCategories()),
		);

		$updateStr = $this->_source->Table('articles')->GetSqlUpdate($obj, 'mae', null, $addFields);
		if (!strlen($updateStr)) return true;

		$num = (bool)$this->_source->exec("update %%article_entry%% mae
										      set
									              " .$updateStr. "
										      " .($sqlFilter['where'] ? " WHERE ". $sqlFilter['where'] : ""). "
									     ");

		if ($num)
		{
			Mozg_Mapper::Get('Tags')->Save('articles', $obj->GetId(), $obj->GetTags());
			$this->SetEntryCategories($obj->GetId(), $obj->GetCategories());

			return true;
		}

		return false;
	}

	private function SetEntryCategories($entryId, array $cats)
	{
		$cats = array_unique(array_map('intval', $cats));
		$entryId = (int)$entryId;

		$this->_source->exec("delete
									from
										%%article_category%%
					            	where
					            		entry_id = " .$entryId );

		if (sizeof($cats))
		{
			$insSql = '';
			foreach ($cats as $catId)
			{
				$insSql .= '(' .$entryId. ', ' .$catId. '),';
			}

			$this->_source->exec("insert ignore into %%article_category%%(entry_id, category_id)
				            values
				            " .rtrim($insSql, ','));
		}
	}

	protected function Prepare(Mozg_Property_Params $obj)
	{
		if ($obj->GetBlogId())
		{
			$obj->SetIsMain(0);
			$obj->SetUrl(null);
			$obj->SetCategories(array());
		}

		$relatedEntries = array_unique(array_map("intval", $obj->GetRelatedEntries()));
		if (($key = array_search($obj->GetId(), $relatedEntries)) !== false)
		{
			unset($relatedEntries[$key]);
		}
		$obj->SetRelatedEntries($relatedEntries);

        return true;
	}

    public function CheckUrl($id, $url)
    {
    	$filter = $this->GetFilter();
    	$filter->SetUrl($url);

		$obj = $this->GetOne($filter);
        return $obj && ($obj->GetId() != $id);
    }

    protected function TrunslateUrl($url)
    {
        return Mozg::Lib('str')->GetTraslit($url);
    }

    public function Delete($filter = null)
    {
		$sqlFilter = $this->GetSqlFromFilter($filter);

        $num = (bool)$this->_source->exec("DELETE
        											mae, maec, mac, mt
		        								FROM
		        									%%article_entry%% mae
		        										left join %%article_entry_comment%% maec on (mae.id = maec.entry_id)
		        										left join %%article_category%% mac on (mae.id = mac.entry_id)
		        										left join %%tag%% mt on (mae.id = mt.id AND area = 'articles')
		        								" .($sqlFilter['where'] ? " WHERE ". $sqlFilter['where'] : ""). "
		        								");
    	if ($num)
    	{
    		return true;
    	}

    	return false;
    }
}